/**
 * 
 */
package demo.mail;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.mail.Authenticator;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.util.ByteArrayDataSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import demo.servlet.util.ContentType;
import demo.util.PropertiesLoader;

/**
 * @author roger.xu
 * 
 */
public class MailService {

    private static final Log _log = LogFactory.getLog(MailService.class.getSimpleName());

    enum MailType {
        TEXT, HTML, MULTI_PART
    }

    public static Session getSession() throws IOException {
        final Properties props = PropertiesLoader.loadProperties("mail.properties");
        final Session session = getSession(props);
        return session;
    }

    public static Session getSession(final Properties props) throws IOException {
        // props.put("mail.transport.protocol", "smtp");
        final String user = props.getProperty("mail.smtp.user");
        final String password = props.getProperty("password");
        final PasswordAuthentication pa = new PasswordAuthentication(user, password);
        final Authenticator auth = new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return pa;
            }
        };

        final Session session = Session.getDefaultInstance(props, auth);
        return session;
    }

    public static void sendAsPlainText(final Session session, final String from, final String to, final String cc,
            final String subject, final String content) throws IOException, MessagingException {

        send(session, MailType.TEXT, from, to, cc, subject, content);
    }

    public static void sendAsHtml(final Session session, final String from, final String to, final String cc,
            final String subject, final String content) throws IOException, MessagingException {

        send(session, MailType.HTML, from, to, cc, subject, content);
    }

    public static void sendAsRichHtml(final Session session, final String from, final String to, final String cc,
            final String subject, final String content) throws IOException, MessagingException {

        send(session, MailType.MULTI_PART, from, to, cc, subject, content);
    }

    private static void send(final Session session, final MailType mailType, final String from, final String to,
            final String cc, final String subject, final String content) throws IOException, MessagingException {

        final Message message = getMessage(session, from, to, cc, subject);

        if (content != null) {
            switch (mailType) {
            case HTML:
                message.setContent(content, ContentType.HTML);
                break;
            case MULTI_PART:
                // multiPart, the BODY and the embedded image
                final String imageContentID = "icon-info";
                final String imageFileName = "icon-information-blue.gif";
                final Multipart multiPart = getMultiPart(content, imageContentID, imageFileName);

                // attach the multi-part to the message
                message.setContent(multiPart);
                break;
            case TEXT:
            default:
                message.setText(content);
                break;
            }
        }

        Transport.send(message);
    }

    private static Message getMessage(final Session session, final String from, final String to, final String cc,
            final String subject) throws IOException, MessagingException {

        final Message message = new MimeMessage(session);

        if (to != null) {
            final InternetAddress[] toAddrs = InternetAddress.parse(to, false);
            message.setRecipients(Message.RecipientType.TO, toAddrs);
        } else {
            throw new MessagingException("No \"To\" address specified");
        }

        if (cc != null) {
            final InternetAddress[] ccAddrs = InternetAddress.parse(cc, false);
            message.setRecipients(Message.RecipientType.CC, ccAddrs);
        }

        if (subject != null) {
            message.setSubject(subject);
        }

        if (from == null) {
            message.setFrom();
        } else {
            message.setFrom(new InternetAddress(from));
        }

        return message;
    }

    /**
     * The MIME MultiPart subtype has to be "related" (defined in rfc2387). multipart/related means that the message
     * parts should be aggregated to build the whole document and that message parts can reference each other. Usually
     * (but this is not a must) the reference is done using the "Content-ID" header (if you read the RFC carefully you
     * will find out that the reference can be done using any "Content-" header).
     * 
     * @param content
     * @param imagePath
     * @return MultiPart
     * @throws MessagingException
     */
    private static Multipart getMultiPart(final String content, final String imageContentID, final String imageFileName) throws MessagingException {
        // multiPart, the BODY and the embedded image
        final Multipart multiPart = new MimeMultipart("related");

        // first part (the html)
        final BodyPart htmlPart = new MimeBodyPart();
        htmlPart.setContent(String.format("<img src=\"cid:%s\" /> %s", imageContentID, content), ContentType.HTML);

        // add it
        multiPart.addBodyPart(htmlPart);

        // second part (the image)
        final BodyPart imgPart = new MimeBodyPart();
        // load the image
        final DataHandler imgDataHandler = getImageDataHandler(imageFileName);
        imgPart.setDataHandler(imgDataHandler);
        imgPart.setHeader("Content-ID", String.format("<%s>", imageContentID));
        imgPart.setFileName(imageFileName);

        // add it
        multiPart.addBodyPart(imgPart);

        return multiPart;
    }

    private static DataHandler getImageDataHandler(final String imageFileName) {

        final InputStream is = MailService.class.getClassLoader().getResourceAsStream(imageFileName);
        DataSource ds = null;
        try {
            ds = new ByteArrayDataSource(is, ContentType.OCTET);
        } catch (IOException e) {
            _log.error(e.getMessage(), e);
        }
        final DataHandler handler = new DataHandler(ds);
        return handler;
    }

}
